﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using DataAbstractor;

namespace DataAbstractorTest
{
    [TestFixture]
    public class MappingTest
    {
        public class AutoMapDestination
        {
            public int A { get; set; }
            public string B { get; set; }
            public decimal C { get; set; }
            public double D { get; set; }
            public int E { get; set; }
        }

        public class AutoMapSource
        {
            public int A { get; set; }
            public string B { get; set; }
            public decimal C { get; set; }
            public double D { get; set; }
        }

        public class AutoMapRecursionDestination
        {
            public AutoMapDestination A { get; set; }
        }

        public class AutoMapRecursionSource
        {
            public AutoMapSource A { get; set; }
        }

        public class AutoMapIterationDestination
        {
            public AutoMapDestination[] A { get; set; }
        }
        
        public class AutoMapIterationListDestination
        {
            public List<AutoMapDestination> A { get; set; }
        }
        
        public class AutoMapIterationLinkedListDestination
        {
            public LinkedList<AutoMapDestination> A { get; set; }
        }

        public class AutoMapIterationSource
        {
            public AutoMapSource[] A { get; set; }
        }

        [Test]
        public void AutoMap()
        {
            var source = new AutoMapSource { A = 1, B = "-2", C = 0.3M, D = -0.6 };
            var result = source.To<AutoMapDestination>();
            Assert.AreEqual(source.A, result.A);
            Assert.AreEqual(source.B, result.B);
            Assert.AreEqual(source.C, result.C);
            Assert.AreEqual(source.D, result.D);
            Assert.AreEqual(0, result.E);
        }

        [Test]
        public void Recursion()
        {
            var source = new AutoMapRecursionSource { A = new AutoMapSource { A = 1, B = "-2", C = 0.3M, D = -0.6 } };
            var result = source.To<AutoMapRecursionDestination>();
            Assert.AreEqual(source.A.A, result.A.A);
            Assert.AreEqual(source.A.B, result.A.B);
            Assert.AreEqual(source.A.C, result.A.C);
            Assert.AreEqual(source.A.D, result.A.D);
            Assert.AreEqual(0, result.A.E);
        }

        [Test]
        public void Iteration()
        {
            var source = new AutoMapIterationSource { A = new[] { new AutoMapSource { A = 1, B = "-2", C = 0.3M, D = -0.6 },
                                                                  new AutoMapSource { A = 9, B = "-8", C = 0.7M, D = -0.6 }}};
            var result = source.To<AutoMapIterationDestination>();
            Assert.AreEqual(2, result.A.Length);
            for (var i = 0; i < result.A.Length; ++i)
            {
                Assert.AreEqual(source.A[i].A, result.A[i].A);
                Assert.AreEqual(source.A[i].B, result.A[i].B);
                Assert.AreEqual(source.A[i].C, result.A[i].C);
                Assert.AreEqual(source.A[i].D, result.A[i].D);
                Assert.AreEqual(0, result.A[i].E);
            }
            
            var result2 = source.To<AutoMapIterationListDestination>();
            Assert.AreEqual(2, result2.A.Count);
            for (var i = 0; i < result2.A.Count; ++i)
            {
                Assert.AreEqual(source.A[i].A, result2.A[i].A);
                Assert.AreEqual(source.A[i].B, result2.A[i].B);
                Assert.AreEqual(source.A[i].C, result2.A[i].C);
                Assert.AreEqual(source.A[i].D, result2.A[i].D);
                Assert.AreEqual(0, result2.A[i].E);
            }
            
            var result3 = source.To<AutoMapIterationLinkedListDestination>();
            Assert.AreEqual(2, result3.A.Count);
            for (var i = 0; i < result3.A.Count; ++i)
            {
            	Assert.AreEqual(source.A[i].A, result3.A.ElementAt(i).A);
                Assert.AreEqual(source.A[i].B, result3.A.ElementAt(i).B);
                Assert.AreEqual(source.A[i].C, result3.A.ElementAt(i).C);
                Assert.AreEqual(source.A[i].D, result3.A.ElementAt(i).D);
                Assert.AreEqual(0, result3.A.ElementAt(i).E);
            }
        }
        
        [Test]
        public void MapTest()
        {
            DataAbstractor.DataAbstractor.Map<AutoMapDestination, AutoMapSource>()
                .Ignore(i => i.A)
                .From(i => i.E).To(i => i.A)
                .From(i => i.B).Value("Hello")
                .Run((destination, source) =>
                    {
                        Assert.AreEqual(1, source.A);
                        Assert.AreEqual("-2", source.B);
                        Assert.AreEqual(0.3M, source.C);
                        Assert.AreEqual(-0.6, source.D);
                        Assert.AreEqual(0, destination.A);
                        Assert.AreEqual("Hello", destination.B);
                        Assert.AreEqual(0.3M, destination.C);
                        Assert.AreEqual(-0.6, destination.D);
                        Assert.AreEqual(1, destination.E);
                        destination.D *= 3;
                    });
            var sourceFields = new AutoMapSource { A = 1, B = "-2", C = 0.3M, D = -0.6 };
            var result = sourceFields.To<AutoMapDestination>();
            Assert.AreEqual(0, result.A);
            Assert.AreEqual("Hello", result.B);
            Assert.AreEqual(0.3M, result.C);
            Assert.AreEqual(-1.8, Math.Round(result.D, 1));
            Assert.AreEqual(1, result.E);
            DataAbstractor.DataAbstractor.RemoveMapping<AutoMapDestination, AutoMapSource>();
        }
    }
}
